package org.op.service.nav;

import java.io.File;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreeNode;

import org.op.service.WwDocumentInfo;
import org.op.service.WwFolderInfo;
import org.op.service.WwInfoObject;

public class SimpleFileNavigationServiceImpl implements FileNavigationService {
	
	protected static final String FILE_PREPENDER = "file:";
	protected static final String FOLDER_PREPENDER = "folder:";
	
	private DefaultTreeModel treeModel;

	public TreeModel loadTreeRoot(TreeModel model, String workspace) throws Exception {
		
		DefaultMutableTreeNode top = null;
		File file = new File(workspace);
		if (file.exists() && file.isDirectory()) {
			
			if (model==null || model.getRoot()==null) {
				String spaceName = file.getName();
				top = new DefaultMutableTreeNode(spaceName);
				WwFolderInfo tfi = new WwFolderInfo(spaceName, workspace);
				tfi.setExpanded(true);
				top.setUserObject(tfi);
				
				model = new FilesystemTreeModel(top);
			} else {
				top = (DefaultMutableTreeNode) model.getRoot();
			}
			
			treeModel = (DefaultTreeModel) model;
			top = getExpandedNode(top);
			// do I need to re-attach the topnode to the model?? I shouldn't have to..
			
			
		} else {
			throw new IOException("No directory exists at " + workspace);
		}
		
		
		return model;
	}
	
	/**
	 *  This is a recursive method to get the children of the specified node, and
	 *    add to the tree model, as necessary (creating the Node object, if necessary)
	 * 
	 *  TODO - this method is too long, refactor
	 * 
	 * @param node
	 * @return
	 */
	@SuppressWarnings("unchecked")
	protected DefaultMutableTreeNode getExpandedNode(DefaultMutableTreeNode node) throws Exception {
		
		if (node.getUserObject() instanceof WwFolderInfo) {
			WwFolderInfo folderInfo = (WwFolderInfo) node.getUserObject();
			System.out.println("Expanding folder " + folderInfo.getName());
			
			Map<String, DefaultMutableTreeNode> existingChildren = getExistingChildren(node);
			
			node.removeAllChildren(); // to refresh
			
			// Get the children of the associated folder in the filesystem
			File parent = new File(folderInfo.getFilepath());
			if (parent.exists()) {		
				File[] files = parent.listFiles();
				for (File child: files) {
					if (isValidWikiFile(child)) {
						String fileName = child.getName();
						
						// eliminate the file extension (what if two . in file name?
						int i = fileName.lastIndexOf('.');
						fileName = fileName.substring(0,i);
						System.out.println("* File child = " + fileName);
						
						DefaultMutableTreeNode childNode = existingChildren.get(FILE_PREPENDER + fileName);
						if (childNode==null) {
							System.out.println("** is a new file.");
							childNode = new DefaultMutableTreeNode(fileName);
							WwDocumentInfo tdi = new WwDocumentInfo(fileName, child.getAbsolutePath());
							childNode.setUserObject(tdi);
						}
	
						node.add(childNode);
					} 
					if (child.isDirectory()) {
						String folderName = child.getName();
						System.out.println("* Folder child = " + folderName);
						DefaultMutableTreeNode childNode = existingChildren.get(FOLDER_PREPENDER + folderName);
						if (childNode==null) {
							System.out.println("** is a new folder.");
							childNode = new DefaultMutableTreeNode(folderName);
							WwFolderInfo tfi = new WwFolderInfo(folderName, child.getAbsolutePath());
							childNode.setUserObject(tfi);
							childNode.setAllowsChildren(true);
						}
						node.add(childNode);
						
						// recurse down this folder
						getExpandedNode(childNode);
					}
				}
			}
		}
		
		return node;
	}
	
	@SuppressWarnings("unchecked")
	protected Map<String, DefaultMutableTreeNode> getExistingChildren(DefaultMutableTreeNode node) {
		
		Map<String, DefaultMutableTreeNode> existingChildren = new HashMap<String, DefaultMutableTreeNode>();
		Enumeration<DefaultMutableTreeNode> children = node.children();  // existing children
		while (children.hasMoreElements()) {
			DefaultMutableTreeNode child = children.nextElement();
			WwInfoObject infoObject = (WwInfoObject) child.getUserObject();
			if (infoObject instanceof WwDocumentInfo) {
				existingChildren.put(FILE_PREPENDER + infoObject.getName(), child);
				System.out.println("* Existing document = " + infoObject.getName());
			}
			if (infoObject instanceof WwFolderInfo) {
				existingChildren.put(FOLDER_PREPENDER + infoObject.getName(), child);
				System.out.println("* Existing folder = " + infoObject.getName());
			}
		}
		
		return existingChildren;
	}

	/**
	 * Filter invalid files
	 * 
	 * @param child
	 * @return
	 */
	protected boolean isValidWikiFile(File child) {
		boolean valid = false;
		
		if (child.isFile()) {
			String fileName = child.getName();
			if (fileName.endsWith(".txt")) {
				valid = true;
			}
		}
		
		return valid;
	}

	/**
	 * 
	 * 
	 */
	public WwInfoObject getAssociatedInfo(TreeNode node) {
		
		WwInfoObject wwInfo = null;
		if (node instanceof DefaultMutableTreeNode) {
			wwInfo = (WwInfoObject) ((DefaultMutableTreeNode)node).getUserObject();
		}
		
		return wwInfo;
		
	}

	public DefaultTreeModel getTreeModel() {
		return treeModel;
	}

}
